package com.enation.app.javashop.core.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.enation.app.javashop.core.aftersale.model.dos.ClaimsDO;
import com.enation.app.javashop.core.aftersale.model.dos.RefundDO;
import com.enation.app.javashop.core.aftersale.model.dos.RefundGoodsDO;
import com.enation.app.javashop.core.aftersale.model.dto.ClaimSkusDTO;
import com.enation.app.javashop.core.aftersale.model.vo.RefundSkuVO;
import com.enation.app.javashop.core.base.rabbitmq.AmqpExchange;
import com.enation.app.javashop.core.goods.model.dos.GoodsDO;
import com.enation.app.javashop.core.member.model.dos.LeaderDO;
import com.enation.app.javashop.core.shop.model.dos.Clerk;
import com.enation.app.javashop.core.shop.model.dto.FixTimeSection;
import com.enation.app.javashop.core.shop.service.ClerkManager;
import com.enation.app.javashop.core.shop.service.impl.OrderReceiveTimeManager;
import com.enation.app.javashop.core.trade.order.model.dos.OrderDO;
import com.enation.app.javashop.core.trade.order.model.enums.OrderTypeEnum;
import com.enation.app.javashop.core.trade.order.model.enums.ServiceStatusEnum;
import com.enation.app.javashop.core.trade.order.model.enums.ShipStatusEnum;
import com.enation.app.javashop.core.trade.order.model.enums.ShipTypeEnum;
import com.enation.app.javashop.core.trade.order.model.vo.OrderSkuVO;
import com.enation.app.javashop.core.wms.model.dos.WmsOrderDO;
import com.enation.app.javashop.core.wms.model.dos.WmsOrderItemsDO;
import com.enation.app.javashop.core.wms.model.dto.SortDirectParam;
import com.enation.app.javashop.core.wms.model.dto.WmsOrderQueryParam;
import com.enation.app.javashop.core.wms.model.enums.LeaderDispatchTypeEnums;
import com.enation.app.javashop.core.wms.model.enums.WmsOrderTypeEnums;
import com.enation.app.javashop.core.wms.model.vo.WmsOrderChangeMsg;
import com.enation.app.javashop.core.wms.model.vo.WmsOrderDetail;
import com.enation.app.javashop.core.wms.model.vo.WmsOrderVO;
import com.enation.app.javashop.core.wms.model.enums.WmsOrderStatusEnums;
import com.enation.app.javashop.core.wms.service.WmsOrderManager;
import com.enation.app.javashop.core.wms.utils.WmsOrderConverter;
import com.enation.app.javashop.core.wms.utils.WmsSqlBuilder;
import com.enation.app.javashop.framework.context.UserContext;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.database.Page;
import com.enation.app.javashop.framework.exception.ServiceException;
import com.enation.app.javashop.framework.redis.transactional.RedisTransactional;
import com.enation.app.javashop.framework.security.model.Seller;
import com.enation.app.javashop.framework.security.model.User;
import com.enation.app.javashop.framework.util.BeanUtil;
import com.enation.app.javashop.framework.util.DateUtil;
import com.enation.app.javashop.framework.util.JsonUtil;
import com.enation.app.javashop.framework.util.SqlUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 出库单管理
 *
 * @author JFeng
 * @date 2020/9/21 17:28
 */
@Service
@Slf4j
public class WmsOrderManagerImpl implements WmsOrderManager {


    @Autowired
    @Qualifier("tradeDaoSupport")
    private DaoSupport daoSupport;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ClerkManager clerkManager;
    @Autowired
    private OrderReceiveTimeManager orderReceiveTimeManager;

    /**
     * 分页查询出库订单列表
     */
    @Override
    public Page<WmsOrderVO> queryDeliverOrderPage(WmsOrderQueryParam param) {
        if (param.getReceiveTimeSeq()!=null) {
            FixTimeSection timeSection = orderReceiveTimeManager.resolveReceiveTimeSeq(param.getSellerId(), param.getReceiveTimeSeq());
            param.setReceiveTime(timeSection.getReceiveTimeStamp());
            param.setReceiveTimeType(timeSection.getReceiveTimeType());
        }
        StringBuilder sql = new StringBuilder();
        List<Object> term = WmsSqlBuilder.wmsOrderPageSql(param, sql);

        Page<WmsOrderVO> page = daoSupport.queryForPage(sql.toString(), param.getPageNo(), param.getPageSize(), WmsOrderVO.class, term.toArray());
        List<WmsOrderVO> wmsOrderVOList = page.getData();
        for (WmsOrderVO wmsOrderVO : wmsOrderVOList) {
            wmsOrderVO.transverse();
        }
        return page;
    }

    /**
     * 待出库订单
     *
     * @param orderDO
     */
    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void acceptOrder(OrderDO orderDO) {
        // 数据幂等
        WmsOrderDO wmsOrderDOExist = this.daoSupport.queryForObject("select * from wms_order where order_sn=? ", WmsOrderDO.class, orderDO.getSn());
        if(wmsOrderDOExist!=null){
             return;
        }
        LeaderDO leaderDO = null;
        if (orderDO.getLeaderId() != null) {
            leaderDO = this.daoSupport.queryForObject(LeaderDO.class, orderDO.getLeaderId());
        }

        WmsOrderDO wmsOrderDO = WmsOrderConverter.convertOrder(orderDO, leaderDO);

        wmsOrderDO.setDeliveryStatus(WmsOrderStatusEnums.CREATED.value());

        // 出库单入库
        log.info(wmsOrderDO.toString());

        this.daoSupport.insert(wmsOrderDO);
        int wmsOrderId = this.daoSupport.getLastId("wms_order");

        // 处理单个sku售后商品
        List<WmsOrderItemsDO> wmsOrderItemsList = new ArrayList<>();
        String itemsJson = orderDO.getItemsJson();
        List<OrderSkuVO> skuList = JsonUtil.jsonToList(itemsJson, OrderSkuVO.class);
        for (OrderSkuVO orderSkuVO : skuList) {
            GoodsDO goodsDO = this.daoSupport.queryForObject("select goods_id,supplier_id,supplier_name from es_goods where goods_id=? ", GoodsDO.class, orderSkuVO.getGoodsId());

            WmsOrderItemsDO wmsOrderItemsDO = new WmsOrderItemsDO();
            BeanUtil.copyProperties(orderSkuVO, wmsOrderItemsDO);
            wmsOrderItemsDO.setImage(orderSkuVO.getGoodsImage());
            wmsOrderItemsDO.setShipNum(orderSkuVO.getNum());
            wmsOrderItemsDO.setOrderSn(orderDO.getSn());
            wmsOrderItemsDO.setShipStatus(ShipStatusEnum.SHIP_NO.value());
            wmsOrderItemsDO.setWmsOrderId(wmsOrderId);
            wmsOrderItemsDO.setSupplierName(goodsDO.getSupplierName());

            if (orderSkuVO.getSpecList() != null) {
                String specJson = JsonUtil.objectToJson(orderSkuVO.getSpecList());
                wmsOrderItemsDO.setSpecJson(specJson);
            }
            wmsOrderItemsList.add(wmsOrderItemsDO);
        }

        this.daoSupport.batchInsert("wms_order_items", wmsOrderItemsList);
    }


    /**
     * 待出库理赔单
     *
     * @param claimsDO
     */
    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @RedisTransactional(acquireTimeout = 3,lockTimeout = 5,retryTimes=3,lockName = "accept_claims",value = "#claimsDO.orderSn")
    public void acceptClaims(ClaimsDO claimsDO) {
        // 数据幂等
        WmsOrderDO wmsOrderDOExist = this.daoSupport.queryForObject("SELECT * FROM wms_order WHERE claims_id=? ", WmsOrderDO.class, claimsDO.getClaimId());
        if(wmsOrderDOExist!=null){
            return;
        }

        String itemsJson = claimsDO.getClaimSkus();
        List<ClaimSkusDTO> newSkuList = JSON.parseArray(itemsJson, ClaimSkusDTO.class);

        WmsOrderDO wmsOrderDOClaims = this.daoSupport.queryForObject("SELECT * FROM wms_order WHERE order_sn=? and delivery_status=? and order_type=?", WmsOrderDO.class,
                claimsDO.getOrderSn(),WmsOrderStatusEnums.CREATED.value(),WmsOrderTypeEnums.CLAIMS.value());

        int wmsOrderId = 0;
        if(wmsOrderDOClaims!=null){
            // 当个订单 多个理赔项 进行商品合并
            wmsOrderId =wmsOrderDOClaims.getDeliveryId();

            String oldJson = wmsOrderDOClaims.getItemsJson();
            List<ClaimSkusDTO> oldSkuList = JSON.parseArray(oldJson, ClaimSkusDTO.class);
            oldSkuList.addAll(newSkuList);

            this.daoSupport.execute("UPDATE wms_order SET items_json=? where delivery_id=?",JSON.toJSONString(oldSkuList),wmsOrderId);

        }else{
            OrderDO orderDO = this.daoSupport.queryForObject("SELECT * FROM es_order WHERE sn = ?", OrderDO.class, claimsDO.getOrderSn());
            LeaderDO leaderDO = null;
            if ( orderDO.getLeaderId() != null) {
                leaderDO = this.daoSupport.queryForObject(LeaderDO.class, orderDO.getLeaderId());
            }

            WmsOrderDO wmsOrderDO = WmsOrderConverter.convertClaims(claimsDO, orderDO, leaderDO);

            wmsOrderDO.setDeliveryStatus(WmsOrderStatusEnums.CREATED.value());

            // 异常单出库时间
            FixTimeSection timeSection=orderReceiveTimeManager.getReceiveTimeBySeller(wmsOrderDO.getSellerId(),null);

            wmsOrderDO.setReceiveTime(timeSection.getReceiveTimeStamp());
            wmsOrderDO.setReceiveTimeType(timeSection.getReceiveTimeType());

            // 出库单入库
            log.info(wmsOrderDO.toString());

            this.daoSupport.insert(wmsOrderDO);
            wmsOrderId = this.daoSupport.getLastId("wms_order");
        }

        // 处理单个sku售后商品
        List<WmsOrderItemsDO> wmsOrderItemsList = new ArrayList<>();

        for (ClaimSkusDTO claimSkusDTO : newSkuList) {
            GoodsDO goodsDO = this.daoSupport.queryForObject("select goods_id,supplier_id,supplier_name from es_goods where goods_id=? ", GoodsDO.class, claimSkusDTO.getGoodsId());

            WmsOrderItemsDO wmsOrderItemsDO = new WmsOrderItemsDO();
            wmsOrderItemsDO.setSkuId(claimSkusDTO.getSkuId());
            wmsOrderItemsDO.setGoodsId(claimSkusDTO.getGoodsId());
            wmsOrderItemsDO.setImage(claimSkusDTO.getThumbnail());
            wmsOrderItemsDO.setShipNum(claimSkusDTO.getCompensationNum());
            wmsOrderItemsDO.setOrderSn(claimsDO.getOrderSn());
            wmsOrderItemsDO.setName(claimSkusDTO.getGoodsName());
            wmsOrderItemsDO.setShipStatus(ShipStatusEnum.SHIP_NO.value());
            wmsOrderItemsDO.setWmsOrderId(wmsOrderId);
            wmsOrderItemsDO.setSupplierName(goodsDO.getSupplierName());
            wmsOrderItemsDO.setSpecJson(claimSkusDTO.getSpecs());

            wmsOrderItemsList.add(wmsOrderItemsDO);
        }

        this.daoSupport.batchInsert("wms_order_items", wmsOrderItemsList);
    }

    /**
     * 取消出库
     *
     * @param refund
     */
    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void cancelOrder(RefundDO refund) {
        WmsOrderDO wmsOrderDO = this.daoSupport.queryForObject("select * from wms_order where order_sn=? and delivery_status=? and (order_type= ? or order_type=? ) limit 1", WmsOrderDO.class, refund.getOrderSn(), WmsOrderStatusEnums.CREATED.value(),WmsOrderStatusEnums.READY_OUT.value(), WmsOrderTypeEnums.ORDER.value());
        if (wmsOrderDO == null) {
            return;
        }
        OrderDO orderDO = this.daoSupport.queryForObject("SELECT sn,order_status,service_status,pay_status,items_json FROM es_order WHERE sn = ?", OrderDO.class, refund.getOrderSn());
        if (orderDO.getServiceStatus().equals(ServiceStatusEnum.APPLY.value())) {
            // 整单取消 （取消出库）
            this.jdbcTemplate.update("UPDATE wms_order SET delivery_status=? , items_json=?  WHERE delivery_id=?", WmsOrderStatusEnums.CANCELLED.value(), orderDO.getItemsJson(),wmsOrderDO.getDeliveryId());
            this.jdbcTemplate.update("UPDATE wms_order_items SET ship_status=? WHERE wms_order_id=?", ShipStatusEnum.SHIP_CANCEL.value(), wmsOrderDO.getDeliveryId());
        } else {
            // 单个sku取消 （取消sku出库）
            List<OrderSkuVO> orderSkuVOS = JSON.parseObject(orderDO.getItemsJson(), new TypeReference<List<OrderSkuVO>>() {});
            this.jdbcTemplate.update("UPDATE wms_order  SET items_json=? where delivery_id= ? ", orderDO.getItemsJson(), wmsOrderDO.getDeliveryId());
            for (OrderSkuVO orderSkuVO : orderSkuVOS) {
                if (orderSkuVO.getServiceStatus().equals(ServiceStatusEnum.APPLY.value())) {
                    this.jdbcTemplate.update("UPDATE wms_order_items SET ship_status=? WHERE wms_order_id=? and sku_id=?", ShipStatusEnum.SHIP_CANCEL.value(), wmsOrderDO.getDeliveryId(), orderSkuVO.getSkuId());
                }
            }
        }
    }

    /**
     * 设置分拣批次号
     *
     * @param sortDirectParam
     */
    @Override
    public void createSorting(SortDirectParam sortDirectParam) {
        Integer batchSize = sortDirectParam.getBatchSize();
        Integer sellerId = sortDirectParam.getSellerId();
        Integer receiveTimeSeq = sortDirectParam.getReceiveTimeSeq();
        Integer pageNo = 1;

        // 准备出库的订单 只能截止到前一天23点59分
        FixTimeSection timeSection = orderReceiveTimeManager.resolveReceiveTimeSeq(sellerId, receiveTimeSeq);
        Integer receiveTimeType = timeSection.getReceiveTimeType();
        Long receiveTime = timeSection.getReceiveTimeStamp();

        Integer deliveryDate = Integer.valueOf(LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")));

        // C类型生成分拣批次和序列
        List<WmsOrderDO> wmsOrderDOS = sortOrders(sellerId, batchSize, pageNo, receiveTime, receiveTimeType,deliveryDate,receiveTimeSeq);

        // B类型 只更新出库单信息 有自提点自行分拣订单
        List<WmsOrderDO> wmsOrderDOListB = leaderSortOrders(sellerId, receiveTime, receiveTimeType, deliveryDate, receiveTimeSeq);
        wmsOrderDOS.addAll(wmsOrderDOListB);

        Map<String, List<WmsOrderDO>> wmsOrderGroupByShipMobile = wmsOrderDOS.stream().collect(Collectors.toMap(WmsOrderDO::getShipMobile, wmsOrderDO -> Lists.newArrayList(wmsOrderDO),
                (List<WmsOrderDO> newValueList, List<WmsOrderDO> oldValueList) -> {
                    oldValueList.addAll(newValueList);
                    return oldValueList;
                }));
        List<WmsOrderDO> updateWmsOrderList = new ArrayList<>();
        for (Map.Entry<String, List<WmsOrderDO>> entry : wmsOrderGroupByShipMobile.entrySet()) {
            List<WmsOrderDO> wmsOrderDOList = entry.getValue();
            int totalOrder = wmsOrderDOList.size();
            int orderSeq = 1;
            String sortingSeqList="";
            for (WmsOrderDO wmsOrderDO : wmsOrderDOList) {
                wmsOrderDO.setOrderNum(totalOrder);
                wmsOrderDO.setOrderSeq(orderSeq);
                sortingSeqList+=wmsOrderDO.getSortingSeq()+"/";
                orderSeq++;
            }
            if(sortingSeqList.length()>100){
                sortingSeqList = sortingSeqList.substring(0, 100);
            }
            for (WmsOrderDO wmsOrderDO : wmsOrderDOList) {
                wmsOrderDO.setSortingSeqList(sortingSeqList);
            }
            updateWmsOrderList.addAll(wmsOrderDOList);
        }
        // 执行更新
        batchUpdateSort(updateWmsOrderList);

    }


    /**
     * 确认出库
     *
     * @param deliveryIds
     * @param deliveryStatus
     * @param refuseReason
     */
    @Override
    public void outStock(Integer[] deliveryIds, String deliveryStatus, String refuseReason) {
        if (deliveryIds.length == 0) {
            return;
        }
        Seller seller = UserContext.getSeller();
        Clerk clerk = clerkManager.getClerkByMemberId(seller.getUid());

        WmsOrderStatusEnums wmsOrderStatusEnums = WmsOrderStatusEnums.valueOf(deliveryStatus);
        if (wmsOrderStatusEnums.equals(WmsOrderStatusEnums.OUT_FAIL) && StringUtils.isEmpty(refuseReason)) {
            throw new ServiceException("1000", "出库失败需要填写原因!");
        }

        List term = new ArrayList<>();
        String snsStr = SqlUtil.getInSql(deliveryIds, term);
        long now = DateUtil.getDateline();
        // 查询出库单
        List<WmsOrderDO> wmsOrderDOList = this.daoSupport.queryForList("select * from wms_order where delivery_id in (" + snsStr + ") ", WmsOrderDO.class, term.toArray());
        List<String> orderSnList = wmsOrderDOList.stream().filter(wmsOrderDO -> wmsOrderDO.getOrderType().equals(WmsOrderTypeEnums.ORDER.value())).map(WmsOrderDO::getOrderSn).collect(Collectors.toList());

        // 查询退款订单信息  （待发货的订单退款 整单退 单个商品退）
        Map<String, List<RefundDO>> refundMap = getRefundMap(orderSnList);
        // 整合批量更新数据
        List<Object[]> batchArgs = new ArrayList<>();
        for (WmsOrderDO wmsOrderDO : wmsOrderDOList) {
            String outStatus=deliveryStatus;
            if (wmsOrderDO.getDeliveryStatus().equals(WmsOrderStatusEnums.CREATED.value()) ||wmsOrderDO.getDeliveryStatus().equals(WmsOrderStatusEnums.OUT_SUCC.value()) || wmsOrderDO.getDeliveryStatus().equals(WmsOrderStatusEnums.CANCELLED.value()) ||  wmsOrderDO.getDeliveryStatus().equals(WmsOrderStatusEnums.OUT_FAIL.value())) {
                throw new ServiceException("500", "订单：" + wmsOrderDO.getOrderSn() + " 不符合出库条件!");
            }

            // 校验退款
            if(deliveryStatus.equals(WmsOrderStatusEnums.OUT_SUCC.value())){
                //Boolean isRefund = checkRefund(refundMap, wmsOrderDO.getOrderSn(), wmsOrderDO.getDeliveryId());
                // 已退款订单不处理出库
                //if(isRefund){
                //    outStatus=WmsOrderStatusEnums.OUT_FAIL.name();
                //    orderSnList.remove(wmsOrderDO.getOrderSn());
                //}
            }

            // 更新数据
            batchArgs.add(new Object[]{
                    outStatus,
                    now,
                    clerk.getClerkName(),
                    refuseReason,
                    wmsOrderDO.getDeliveryId()});
        }

        this.jdbcTemplate.batchUpdate("UPDATE wms_order SET delivery_status=? , delivery_time=? ,operator_name=? ,refuse_reason=? WHERE delivery_id = ? ", batchArgs);

        // 通知订单已发货
        if(deliveryStatus.contains(WmsOrderStatusEnums.OUT_SUCC.name())){
            WmsOrderChangeMsg wmsOrderChangeMsg = new WmsOrderChangeMsg();
            wmsOrderChangeMsg.setOrderSnList(orderSnList);
            this.amqpTemplate.convertAndSend(AmqpExchange.WMS_ORDER_CHANGE, AmqpExchange.WMS_ORDER_CHANGE + "_ROUTING", wmsOrderChangeMsg);
        }
    }

    private Map<String, List<RefundDO>> getRefundMap(List<String> orderSnList) {
        if (CollectionUtils.isEmpty(orderSnList)) {
            return Maps.newHashMap();
        }
        List refundTerm = new ArrayList<>();
        String orderSnsStr = SqlUtil.getInSql(orderSnList.toArray(), refundTerm);
        List<RefundDO> refundDOS = this.daoSupport.queryForList("select * from es_refund where order_sn in (" + orderSnsStr + ") ", RefundDO.class, refundTerm.toArray());
        return refundDOS.stream().collect(Collectors.toMap(RefundDO::getOrderSn, refundDO -> Lists.newArrayList(refundDO),
                (List<RefundDO> newValueList, List<RefundDO> oldValueList) -> {
                    oldValueList.addAll(newValueList);
                    return oldValueList;
                }));
    }

    private Boolean checkRefund(Map<String, List<RefundDO>> refundMap, String orderSn, Integer deliveryId) {
        Boolean isRefund=false;
        // 出库商品是否已经申请退款
        List<RefundDO> refundDOList = refundMap.get(orderSn);
        if (CollectionUtils.isNotEmpty(refundDOList)) {
            for (RefundDO refundDO : refundDOList) {
                List<RefundGoodsDO> refundGoodsDOS = this.daoSupport.queryForList("select * from es_refund_goods where refund_sn = " + refundDO.getSn(), RefundGoodsDO.class);
                List<WmsOrderItemsDO> orderItemsDOS = this.daoSupport.queryForList("select * from wms_order_items where ship_status='SHIP_NO' and wms_order_id = " + deliveryId, WmsOrderItemsDO.class);
                if (CollectionUtils.isNotEmpty(orderItemsDOS)) {
                    Map<Integer, WmsOrderItemsDO> orderItemsMap = orderItemsDOS.stream().collect(Collectors.toMap(WmsOrderItemsDO::getSkuId, Function.identity()));
                    for (RefundGoodsDO refundGoodsDO : refundGoodsDOS) {
                        Integer skuId = refundGoodsDO.getSkuId();
                        WmsOrderItemsDO wmsOrderItemsDO = orderItemsMap.get(skuId);
                        if (wmsOrderItemsDO != null) {
                            isRefund=true;
                        }
                    }
                }
            }
        }
        return isRefund;
    }


    /**
     * 更新打印次数
     *
     * @param deliveryId
     */
    @Override
    public void updatePrintTimes(Integer[] deliveryId) {

    }

    @Override
    public List<WmsOrderVO> queryList(Integer[] deliveryIds) {
        WmsOrderQueryParam param = new WmsOrderQueryParam();
        param.setDeliveryIds(Arrays.asList(deliveryIds));
        //param.setDeliveryStatus(WmsOrderStatusEnums.READY_OUT.value());
        param.setSellerId(UserContext.getSeller().getSellerId());

        StringBuilder sql = new StringBuilder();
        List<Object> term = WmsSqlBuilder.wmsOrderPageSql(param, sql);
        // 查询出库单
        List<WmsOrderVO> wmsOrderVOList = daoSupport.queryForList(sql.toString(), WmsOrderVO.class, term.toArray());

        List<String> orderSnList = wmsOrderVOList.stream().filter(wmsOrderVO -> wmsOrderVO.getWmsOrderType().equals(WmsOrderTypeEnums.ORDER.value())).map(WmsOrderVO::getOrderSn).collect(Collectors.toList());

        // 查询退款订单信息  （待发货的订单退款 整单退 单个商品退）
        Map<String, List<RefundDO>> refundMap = getRefundMap(orderSnList);

        for (WmsOrderVO wmsOrderVO : wmsOrderVOList) {
            // 校验退款
         checkRefund(refundMap, wmsOrderVO.getOrderSn(), wmsOrderVO.getDeliveryId());

            // 数据转换
            wmsOrderVO.transverse();

            //wmsOrderVO.setItemsList(orderItemsMap.get(wmsOrderVO.getDeliveryId()));
        }
        return wmsOrderVOList;
    }

    @Override
    public void orderSended(OrderDO order) {
        log.info("订单主动发货：" + order);
        this.daoSupport.execute("UPDATE wms_order SET delivery_status=? , delivery_time=? ,operator_name=? WHERE order_sn = ? and order_type=?  ",
                WmsOrderStatusEnums.OUT_SUCC.value(), order.getShipTime(), "ORDER_SYS", order.getSn(), WmsOrderTypeEnums.ORDER.value());
    }

    @Override
    public void updateReceiveTimeByIds(Integer[] deliveryIds, String receiveDay) {
        LocalDate localDate = LocalDate.parse(receiveDay, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        long receiveTime = LocalDateTime.of(localDate, LocalTime.of(17, 0)).toInstant(ZoneOffset.of("+8")).toEpochMilli() / 1000;

        List term = new ArrayList<>();
        String snsStr = SqlUtil.getInSql(deliveryIds, term);
        // 查询出库单
        List<WmsOrderDO> wmsOrderDOList = this.daoSupport.queryForList("select * from wms_order where delivery_id in (" + snsStr + ") ", WmsOrderDO.class, term.toArray());
        if (CollectionUtils.isEmpty(wmsOrderDOList)) {
            return;
        }
        // 整合批量更新数据
        List<Object[]> batchArgs = new ArrayList<>();
        for (WmsOrderDO wmsOrderDO : wmsOrderDOList) {
            if(wmsOrderDO.getDeliveryStatus().equals(WmsOrderStatusEnums.CREATED.value())){
                throw new ServiceException("10000",wmsOrderDO.getOrderSn()+",【待出库】订单不能修改发货时间！");
            }
            if(wmsOrderDO.getReceiveTime().equals(receiveTime)){
                throw new ServiceException("10000",wmsOrderDO.getOrderSn()+",订单没有变更发货时间！");
            }

            // 更新数据
            batchArgs.add(new Object[]{
                    WmsOrderStatusEnums.CREATED.value(),
                    receiveTime,
                    wmsOrderDO.getDeliveryId()});
        }

        this.jdbcTemplate.batchUpdate("UPDATE wms_order SET delivery_sn=null,sorting_batch=null,sorting_seq=null,delivery_status=? , receive_time=?  WHERE delivery_id = ? ", batchArgs);

    }

    @Override
    public void delayDispatch(Integer[] deliveryIds) {
        List<Object[]> batchArgs = new ArrayList<>();
        for (Integer deliveryId : deliveryIds) {
            // 更新数据
            batchArgs.add(new Object[]{
                    WmsOrderStatusEnums.DELAY_OUT.value(),deliveryId,
                    WmsOrderStatusEnums.READY_OUT.value()});
        }

        this.jdbcTemplate.batchUpdate("UPDATE wms_order SET delivery_status=?  WHERE delivery_id = ? and delivery_status=? ", batchArgs);
    }

    @Override
    public void cancelClaims(ClaimsDO claimsDO) {
        WmsOrderDO wmsOrderDOExist = this.daoSupport.queryForObject("SELECT * FROM wms_order WHERE claims_id=? ", WmsOrderDO.class, claimsDO.getClaimId());
        if(wmsOrderDOExist==null){
            return;
        }
        // 撤销出库
        this.daoSupport.execute("UPDATE wms_order SET delivery_status=? ,operator_name=? WHERE  claims_id=?  ",
                WmsOrderStatusEnums.CANCELLED.value(), claimsDO.getAuditMemberName(), claimsDO.getClaimId());
    }

    // ====================================================================================================
    // ================  私有方法区   ======================================================================
    // ====================================================================================================


    private List<WmsOrderDO> leaderSortOrders(Integer sellerId,  Long receiveTime, Integer receiveTimeType, Integer deliveryDate,Integer receiveTimeSeq) {
        String deliverSnPrefix = "CK-" + deliveryDate + "-"+receiveTimeSeq+ "-";
        List<WmsOrderDO> wmsOrderDOS = this.daoSupport
                .queryForList(
                        "SELECT wo.* FROM wms_order wo  " +
                                "LEFT JOIN es_leader ld ON  wo.site_id=ld.leader_id " +
                                "WHERE wo.seller_id = ? AND wo.delivery_status=? AND  ((wo.receive_time = ?  and wo.receive_time_type=? ) or (wo.receive_time is null and wo.receive_time_type is null ) )  AND ld.dispatch_type = ?" +
                                "ORDER BY ld.ship_priority DESC , ld.leader_name DESC ",
                        WmsOrderDO.class, sellerId, WmsOrderStatusEnums.CREATED.value(), receiveTime,receiveTimeType, LeaderDispatchTypeEnums.SELF_BATCH.name());
        int seq=1;
        for (WmsOrderDO wmsOrderDO : wmsOrderDOS) {
            wmsOrderDO.setSortingBatch(66);
            wmsOrderDO.setSortingSeq(seq);
            wmsOrderDO.setDeliveryStatus(WmsOrderStatusEnums.READY_OUT.value());
            wmsOrderDO.setDeliverySn(deliverSnPrefix + wmsOrderDO.getSortingBatch() + "-" + wmsOrderDO.getSortingSeq());
            wmsOrderDO.setDeliveryDate(deliveryDate);
            wmsOrderDO.setDispatchType(LeaderDispatchTypeEnums.SELF_BATCH.name());
            seq++;
        }
        return wmsOrderDOS;
    }

    private List<WmsOrderDO> sortOrders(Integer sellerId, Integer batchSize, Integer pageNo, Long receiveTime, Integer receiveTimeType,Integer deliveryDate,Integer receiveTimeSeq) {

        String deliverSnPrefix = "CK-"+sellerId+"-" + deliveryDate + "-"+receiveTimeSeq+ "-";

        // 查询所有C模式 待分拣出库单 (【条件】 指定商户未出库订单)(【排序】 配送自提点优先级-降序 ，自提站点-降序)
        List<WmsOrderDO> wmsOrderDOS= this.daoSupport
                .queryForList("SELECT wo.* FROM wms_order wo  " +
                                "LEFT JOIN es_leader ld ON  wo.site_id=ld.leader_id " +
                                "WHERE wo.seller_id = ? AND wo.delivery_status=? AND wo.receive_time = ?  AND wo.receive_time_type=? AND (ld.dispatch_type = ? or wo.site_id is null) " +
                                "ORDER BY ld.ship_priority DESC , ld.leader_name DESC ,wo.ship_mobile DESC",
                        WmsOrderDO.class, sellerId, WmsOrderStatusEnums.CREATED.value(), receiveTime,receiveTimeType, LeaderDispatchTypeEnums.SELF_GLOBAL.name());

        int batch=1;
        int seq=1;
        int flag=0;
        for (int i = 0; i < wmsOrderDOS.size(); i++) {
            WmsOrderDO wmsOrderDO = wmsOrderDOS.get(i);
            wmsOrderDO.setSortingBatch(batch);
            wmsOrderDO.setSortingSeq(seq);
            wmsOrderDO.setDeliveryStatus(WmsOrderStatusEnums.READY_OUT.value());
            wmsOrderDO.setDeliverySn(deliverSnPrefix + batch + "-" + seq);
            wmsOrderDO.setDeliveryDate(deliveryDate);
            wmsOrderDO.setDispatchType(LeaderDispatchTypeEnums.SELF_GLOBAL.name());
            if(wmsOrderDO.getShippingType().equals(ShipTypeEnum.GLOBAL.name()) && wmsOrderDO.getShipAddr().contains("衢山")){
               wmsOrderDO.setRemarks("衢山镇-直送到家");
            }
            // 序号自增
            seq++;
            // 判断出库单收货人是否跨批次
            if(seq>batchSize){
                batch++;
                seq=1;
                flag=i;
                // 找到跨界点最早的订单位置
                i=resetCount(wmsOrderDOS,i);
                if((flag-i+1)>=batchSize){
                    i=flag;
                }
            }
        }

        return wmsOrderDOS;
    }

    private int resetCount(List<WmsOrderDO> wmsOrderDOS, Integer mark) {
        WmsOrderDO currentWmsOrder = wmsOrderDOS.get(mark);
        WmsOrderDO nextWmsOrder = wmsOrderDOS.get(mark+1);

        if(nextWmsOrder!=null && currentWmsOrder.getShipMobile().equals(nextWmsOrder.getShipMobile())){
            //收货人跨批次处理 i值需要往回拨
            mark = preCheck(wmsOrderDOS, mark);
            mark=mark-1;
        }
        return mark;
    }

    private int preCheck(List<WmsOrderDO> wmsOrderDOS, Integer mark) {
        WmsOrderDO currentWmsOrder = wmsOrderDOS.get(mark);
        WmsOrderDO preWmsOrder = wmsOrderDOS.get(mark-1);
        if(preWmsOrder.getShipMobile().equals(currentWmsOrder.getShipMobile())){
            mark=preCheck(wmsOrderDOS,mark-1);
        }
        return mark;
    }


    private void batchUpdateSort(List<WmsOrderDO> list) {
        String sql = "UPDATE wms_order SET sorting_batch=? , sorting_seq=? , delivery_status=? ,delivery_sn=?,delivery_date=? ,delivery_type=?,order_num=? ,order_seq=?,sorting_seq_list=?,remarks=? WHERE delivery_id=?";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public int getBatchSize() {
                return list.size();
            }

            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                WmsOrderDO wmsOrderDO = list.get(i);
                ps.setInt(1, wmsOrderDO.getSortingBatch());
                ps.setInt(2, wmsOrderDO.getSortingSeq());
                ps.setString(3, wmsOrderDO.getDeliveryStatus());
                ps.setString(4, wmsOrderDO.getDeliverySn());
                ps.setInt(5, wmsOrderDO.getDeliveryDate());
                ps.setString(6, wmsOrderDO.getDispatchType());
                ps.setInt(7, wmsOrderDO.getOrderNum());
                ps.setInt(8, wmsOrderDO.getOrderSeq());
                ps.setString(9, wmsOrderDO.getSortingSeqList());
                ps.setString(10, wmsOrderDO.getRemarks()==null?"":wmsOrderDO.getRemarks());
                // 条件
                ps.setInt(11, wmsOrderDO.getDeliveryId());
            }
        });
    }

}

